什么是反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能过调用他的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能成为Java语言的反射机制。
反射其实就是把Java类中的各种成分映射成一个个Java的对象。比如一个类包括成员变量,方法,构造方法,接口,包等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象进行操作。首先需要了解类的加载过程,
类加载过程和对象创建过程
类加载过程
JVM会先去方法区中找有没有相应类的.class存在,如果有直接使用就可以,如果没有,需要把相关类的.class文件加载到方法区。
.class文件加载到方法区时,会分成两部分加载,先加载非静态内容,再加载静态内容
加载非静态内容:把.class中的所有非静态内容加载到方法区下的非静态区域内
加载静态内容:
把.class文件中的所有静态内容加载到方法区的静态区域内
静态内容加载完成后,对所有静态变量进行默认初始化
所有的静态变量默认初始化完成之后,再进行显示初始化。
当静态区域下的所有静态变量显示初始化完后,执行静态代码段。
静态区域下的静态代码快执行完毕之后,整个类的加载就完成了。
对象创建过程
在堆内存中开辟一块空间
给开辟的空间分配一个地址
把对象的所有非静态成员变量加载到所开辟的空间下
所有的非静态成员加载完成之后,对所有的非静态成员变量进行默认初始化
默认初始化完成之后,调用构造函数
构造函数入栈执行时,先执行构造函数中的隐式三步,再执行构造函数。
隐式三步:
执行super语句
对开辟空间下所有非静态成员变量进行显示初始化
执行构造代码块
构造函数执行完毕并弹栈之后,把空间分配的地址赋值给一个引用对象。
Class类
Class类实现了Serializable, AnnotatedElement, GenericDeclaration, Type这四个接口
final函数头,不可继承
123public final class Class<T>extends Objectimplements Serializable, GenericDeclaration, Type, AnnotatedElementClass类实例表示Java程序中运行的类或者接口,枚举是类的一种而注解是接口的一种。同样数组也是一个可以被反射为Class对象,从而被所有数组来共享其维度和数据。8种基本类型也可以看做为class对象。
需要注意的是Class类没有公有的构造方法,Class对象是有JVM及ClassLoader记载类的过程中自动创建的。
方法列表
- 静态方法
返回值 | 方法及描述 |
---|---|
static Class<?> | forName(String className) Returns the Class object associated with the class or interface with the given string name. |
static Class<?> | forName(String name, boolean initialize, ClassLoader loader) Returns the Class object associated with the class or interface with the given string name, using the given class loader. |
- 常用实例方法
返回值 | 方法及描述 |
---|---|
Class<?>[] | getClasses() Returns an array containing Class objects representing all the public classes and interfaces that are members of the class represented by this Class object |
ClassLoader | getClassLoader() Returns the class loader for the class. |
Constructor |
getConstructor(Class<?>… parameterTypes) Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. |
Field | getField(String name) Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object. |
Class<?>[] | getInterfaces() Determines the interfaces implemented by the class or interface represented by this object. |
Method | getMethod(String name, Class<?>… parameterTypes) Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. |
T | newInstance() Creates a new instance of the class represented by this Class object. |
反射的使用
实际上,我们获取Class对象的方法有三种:
Object对象的getClass()方法
任何数据类型都有一个都有一个“静态”的class属性
通过Class类的静态方法:forName(String className)
实际中我们需要使用反射来动态的生成对象,而如果已经有了对象也就不需要反射了,多以第一种很少用,第二种需要提前有类的包,同样导入了类的包可以直接创建。因此常用的是第三种,通过一个字符串来将要反射的类的信息传递进来动态生成对象。
|
|
通过反射获取构造方法并使用
Student类:
|
|
运行结果:
|
|
获得成员变量并调用
- 批量的:
public Method[] getMethods():获取所有”公有方法”;(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的) 获取单个的:
public Method getMethod(String name,Class<?>… parameterTypes),name : 方法名;Class … : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>… parameterTypes)调用方法:
Method –> public Object invoke(Object obj,Object… args): obj : 要调用方法的对象,args:调用方式时所传递的实参
Student1类:
|
|
测试类:
|
|
输出结果:
|
|
反射main方法
Student2类
|
|
测试类:
|
|
其中调用main方法时,第一个参数是对象的类型,由于为静态类,则设置为null就可以,第二个参数是方法参数,注意强制转换。
通过反射运行配置文件的内容
Student4类
|
|
a.txt文件
|
|
测试类:
|
|
更新要反射的类只操作配置文件就可以,便于后期维护和更新。
反射越过泛型检查
泛型用于编译器,编译过后进行泛型擦除,可以通过反射来越过泛型检查。
|
|